unit uMouseHandler ;

interface

uses
  Classes,
  Graphics,
  Contnrs,
  Forms,
  Menus,
  Types,
  uBasic,
  uObjects,
  uPlacement,
  uNetDrag,
  dlgMeda,
  GDIPAPI,
  GDIPOBJ ;

type

  TMedaDrawState = ( dwsIdle, dwsBend, dwsLine, dwsHorizontal, dwsVertical, dwsURLL, dwsULLR, dswConnected ) ;
  TMedaDragState = ( dgsIdle, dgsHorizontal, dgsVertical ) ;
  TMedaRightState = ( rgtIdle ) ;

  TMouseHandler = class
  private
    fGrid : integer ;
    fViewList : TMedaViewList ;
  public
    constructor Create( aGrid : integer ) ;
    destructor Destroy ; override ;

    procedure Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; virtual ;
    procedure Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; virtual ;
    procedure Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; virtual ;
    procedure KeyDown( var Key : Word ; Shift : TShiftState ) ; virtual ;
  end ;

  TMouseDragger = class( TMouseHandler )
  private
    fState : TMedaDragState ;
  public
    constructor Create( aGrid : integer ) ;
    procedure Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
  end ;

  TMouseSchematicDragger = class( TMouseDragger )
  end ;

  TMousePCBDragger = class( TMouseDragger )
  end ;

  TMouseDrawer = class( TMouseHandler )
  private
    fState : TMedaDrawState ;
    fShift : TShiftState ;
    fModule : TMedaModule ;
    fPart : TMedaPart ;
    fObject : TMedaObject ;
    fPort : TMedaPort ;
    fNet : TMedaNet ;
    fPlace : TGUID ;

    procedure AddPoint( aPoint : TGPPointF ) ; virtual ; abstract ;
    procedure NewState( aPos : TGPPointF ) ;
    function GetLastPoint : TGPPointF ; virtual ; abstract ;
    procedure SetLastPoint( const Value : TGPPointF ) ; virtual ; abstract ;
  public
    constructor Create( aGrid : integer ) ;
    property LastPoint : TGPPointF read GetLastPoint write SetLastPoint ;
    procedure Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
  end ;

  TMouseSchematicDrawer = class( TMouseDrawer )
  private
    fLine : TMedaWire ;
    procedure AddPoint( aPoint : TGPPointF ) ; override ;
    function GetLastPoint : TGPPointF ; override ;
    procedure SetLastPoint( const Value : TGPPointF ) ; override ;
  public
    procedure Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure KeyDown( var Key : Word ; Shift : TShiftState ) ; override ;
  end ;

  TMousePCBDrawer = class( TMouseDrawer )
  private
    fTrack : TMedaTrack ;
    fTrans : TMedaTransform ;
    procedure AddPoint( aPoint : TGPPointF ) ; override ;
    function GetLastPoint : TGPPointF ; override ;
    procedure SetLastPoint( const Value : TGPPointF ) ; override ;
  public
    procedure Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure KeyDown( var Key : Word ; Shift : TShiftState ) ; override ;
  end ;

  TMouseLinker = class( TMouseHandler )
  private
    fObject : TMedaObject ;
    fLinkedObject : TMedaObject ;
  public
    constructor Create( aGrid : integer ) ;
    procedure Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
  end ;

  TMouseSelector = class( TMouseHandler )
  private
  public
    procedure Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
  end ;

  TMouseConnector = class( TMouseHandler )
  private
  public
    procedure Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
  end ;

  TMouseRight = class( TMouseHandler )
  private
    fState : TMedaRightState ;
  public
    constructor Create( aGrid : integer ) ;
    procedure Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
    procedure Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ; override ;
  end ;

  // factories

  TMouseFactory = class
  public
    function CreateSelector( aGrid : integer ) : TMouseSelector ; virtual ; abstract ;
    function CreateDragger( aGrid : integer ) : TMouseDragger ; virtual ; abstract ;
    function CreateDrawer( aGrid : integer ) : TMouseDrawer ; virtual ; abstract ;
    function CreateConnector( aGrid : integer ) : TMouseConnector ; virtual ; abstract ;
    function CreateLinker( aGrid : integer ) : TMouseLinker ; virtual ; abstract ;
    function CreateRight( aGrid : integer ) : TMouseRight ; virtual ; abstract ;
  end ;

  TMouseSchematicFactory = class( TMouseFactory )
  public
    function CreateSelector( aGrid : integer ) : TMouseSelector ; override ;
    function CreateDragger( aGrid : integer ) : TMouseDragger ; override ;
    function CreateDrawer( aGrid : integer ) : TMouseDrawer ; override ;
    function CreateConnector( aGrid : integer ) : TMouseConnector ; override ;
    function CreateLinker( aGrid : integer ) : TMouseLinker ; override ;
    function CreateRight( aGrid : integer ) : TMouseRight ; override ;
  end ;

  TMousePCBFactory = class( TMouseFactory )
  public
    function CreateSelector( aGrid : integer ) : TMouseSelector ; override ;
    function CreateDragger( aGrid : integer ) : TMouseDragger ; override ;
    function CreateDrawer( aGrid : integer ) : TMouseDrawer ; override ;
    function CreateConnector( aGrid : integer ) : TMouseConnector ; override ;
    function CreateLinker( aGrid : integer ) : TMouseLinker ; override ;
    function CreateRight( aGrid : integer ) : TMouseRight ; override ;
  end ;

implementation

uses
  uMain,
  SysUtils,
  Controls,
  uLayout
  ;

{ TMouseHandler }

constructor TMouseHandler.Create( aGrid : integer ) ;
begin
  inherited Create ;
  fViewList := TMedaViewList.Create ;
  fGrid := aGrid ;
end ;

destructor TMouseHandler.Destroy ;
begin
  fViewList.Free ;
  inherited ;
end ;

procedure TMouseHandler.Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  i                 : integer ;
begin
  if assigned( aViewList ) then begin
    fViewList.Assign( aViewList ) ;
    for i := 0 to fViewList.Count - 1 do
      fViewList[ i ].SetSelection( triTrue ) ;
  end ;
end ;

procedure TMouseHandler.Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
end ;

procedure TMouseHandler.KeyDown( var Key : Word ; Shift : TShiftState ) ;
begin
end ;

procedure TMouseHandler.Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  i                 : integer ;
begin
  for i := 0 to fViewList.Count - 1 do
    fViewList[ i ].SetSelection( triFalse ) ;
  Screen.Cursor := crDefault ;
end ;

{ TMouseDragger }

constructor TMouseDragger.Create( aGrid : integer ) ;
begin
  inherited Create( aGrid ) ;
  fState := dgsIdle ;
end ;

procedure TMouseDragger.Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  iView             : TMedaView ;
  iOffset           : TGPPointF ;
  i                 : integer ;
begin
  inherited ;
  if fViewList.Count = 0 then
    Exit ;

  iOffset := fViewList.FirstView.Owner.Transforms[ 0 ].Position ;
  iOffset.X := aPos.X - iOffset.X ;
  iOffset.Y := aPos.Y - iOffset.Y ;
  ScaleDown( iOffset, fGrid ) ;
  ScaleUp( iOffset, fGrid ) ;
  for i := 0 to fViewList.Count - 1 do begin
    iView := fViewList[ i ] ;
    Assert( assigned( iView ) ) ;
    iView.Helper := nil ;
    if iView is TMSPTrack then
      iView.Helper := TTrackDragger.Create( fGrid, iOffset )
    else if iView is TMSPWire then
      iView.Helper := TLineDragger.Create( fGrid, iOffset )
    else if iView is TMSPPin then
      iView.Helper := TPinDragger.Create( fGrid, iOffset )
    else if iView is TMSPBank then
      iView.Helper := TBoxDragger.Create( fGrid, iOffset )
    else if iView is TMSPShape then
      iView.Helper := TBoxDragger.Create( fGrid, iOffset ) ;
  end ;
//      else if iView is TMSPPad then
//        iView.Helper := TPadDragger.Create( fGrid, iOffset )
//      else if iView is TMSPCopper then
//        iView.Helper := TCopperDragger.Create( fGrid, iOffset )
//      else if iView is TMSPLabel then
//        iView.Helper := TLabelDragger.Create( fGrid, iOffset )
end ;

procedure TMouseDragger.Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  iCursor           : TCursor ;
  iView             : TMedaView ;
  i                 : integer ;
begin
  if fViewList.Count = 0 then
    Exit ;

  iCursor := crNo ;
  try
    for i := 0 to fViewList.Count - 1 do begin
      iView := fViewList[ i ] ;
      //      if ( not assigned( aViewList ) ) or ( aViewList.Count = 0 ) or ( aViewList[ 0 ] = iView ) then begin
      if assigned( iView.Helper ) then
        iCursor := TDraggerHelper( iView.Helper ).Move( iView, Shift, aPos ) ;
      //      end ;
    end ;
  finally
    Screen.Cursor := iCursor ;
  end ;
end ;

procedure TMouseDragger.Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  iView             : TMedaView ;
  i                 : integer ;
begin
  inherited ;
  for i := 0 to fViewList.Count - 1 do begin
    iView := fViewList[ i ] ;
    Assert( assigned( iView ) ) ;
    if assigned( iView.Helper ) then
      iView.Helper.Free ;
    iView.Helper := nil ;
  end ;
  fState := dgsIdle ;
end ;

{ TMouseDrawer }

procedure TMouseDrawer.NewState( aPos : TGPPointF ) ;
var
  iPivot            : TGPPointF ;
begin
  iPivot := LastPoint ;
  if abs( aPos.X - iPivot.X ) > abs( aPos.Y - iPivot.Y ) + fGrid div 2 then
    fState := dwsHorizontal
  else if abs( aPos.Y - iPivot.Y ) > abs( aPos.X - iPivot.X ) + fGrid div 2 then
    fState := dwsVertical ;
end ;

constructor TMouseDrawer.Create( aGrid : integer ) ;
begin
  inherited Create( aGrid ) ;
  fState := dwsIdle ;
end ;

procedure TMouseDrawer.Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
  inherited ;
  if fViewList.Count > 0 then begin
    fObject := fViewList[ 0 ].Owner as TMedaObject ;
    fModule := fObject.Module ;
    if not assigned( fModule ) then
      Exit ;
    if not assigned( fObject ) then
      Exit ;
  end
  else
    Exit ;
end ;

{ TMouseSchematicDrawer }

procedure TMouseSchematicDrawer.AddPoint( aPoint : TGPPointF ) ;
begin
  inherited ;

  fLine := fNet.AddWire ;
  fLine.SetPoints( aPoint, aPoint ) ;
  fLine.PlaceRef := fPlace ;
  fLine.PlaceMe ;
end ;

function TMouseSchematicDrawer.GetLastPoint : TGPPointF ;
var
  p                 : TGPPointF ;
begin
  if assigned( fLine ) then
    fLine.GetPoints( p, Result ) ;
end ;

procedure TMouseSchematicDrawer.SetLastPoint( const Value : TGPPointF ) ;
var
  p1, p2            : TGPPointF ;
begin
  if assigned( fLine ) then begin
    fLine.GetPoints( p1, p2 ) ;
    fLine.SetPoints( p1, Value ) ;
  end ;
  inherited ;
end ;

procedure TMouseSchematicDrawer.Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
  inherited ;
  if fState in [ dwsIdle ] then begin
    ScaleDown( aPos, fGrid ) ;
    ScaleUp( aPos, fGrid ) ;
    if fObject is TMedaPin then begin
      fPort := TMedaPin( fObject ).Port ;
      if assigned( fPort ) then begin
        fPart := TMedaPart( fPort.Parent ) ;
        Assert( assigned( fPart ), 'Port has no Part' ) ;
        fModule := fPart.Module ;       // scope of the port
        Assert( assigned( fModule ), 'Part has no Module' ) ;
        if assigned( fPort.Net ) then
          fNet := fPort.Net
        else begin
          fNet := fModule.AddNet ;
          fPort.Net := fNet ;
        end ;
        aPos := fObject.GetConnector( aPos ) ;
        fPlace := fObject.PlaceRef ;
        fState := dwsLine ;
        AddPoint( aPos ) ;
      end
      else begin
        Screen.Cursor := crNo ;
        Exit ;
      end ;
    end
    else if fObject is TMedaWire then begin
      fNet := ( fObject as TMedaWire ).Net ;
      ScaleDown( aPos, fGrid ) ;
      ScaleUp( aPos, fGrid ) ;
      aPos := fObject.GetConnector( aPos ) ;
      fPlace := fObject.PlaceRef ;
      fState := dwsLine ;
      AddPoint( aPos ) ;
    end
    else begin
      Screen.Cursor := crNo ;
      Exit ;
    end ;
    Assert( assigned( fNet ), 'Port has no Net' ) ;
    fNet.SetSelection( TriTrue ) ;
    Screen.Cursor := ord( crDrawWand ) ;
  end ;
end ;

procedure TMouseSchematicDrawer.KeyDown( var Key : Word ; Shift : TShiftState ) ;
begin
  if ( ssCtrl in Shift ) and not ( ssCtrl in fShift ) then
    fState := dwsBend ;
  fShift := Shift ;
end ;

procedure TMouseSchematicDrawer.Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;

  function Connect : boolean ;
  var
    aObject         : TMedaViewable ;
    i               : integer ;
  begin
    Result := False ;
    if assigned( aViewList ) then
      for i := 0 to aViewList.Count - 1 do begin
        aObject := aViewList[ i ].Owner ;
        if assigned( aObject ) and ( aObject <> fObject ) then begin
          if ( aObject is TMedaWire ) and ( fObject is TMedaWire ) then
            Result := True
          else if aObject is TMedaPin then
            Result := True ;
          if Result then
            Exit ;
        end ;
      end ;
  end ;
begin
  inherited ;
  if fState <> dwsIdle then begin
    fShift := Shift ;
    ScaleDown( aPos, fGrid ) ;
    ScaleUp( aPos, fGrid ) ;
    //    aPos.X := aPos.X - fOffset.X ;
    //    aPos.Y := aPos.Y - fOffset.Y ;

    if assigned( fNet ) then
      case fState of
        dwsLine : begin
            NewState( aPos ) ;
            if fState <> dwsLine then
              LastPoint := aPos ;
          end ;
        dwsBend : begin
            NewState( aPos ) ;
            if fState <> dwsBend then
              AddPoint( LastPoint ) ;
          end ;
        dwsHorizontal :
          if LastPoint.X <> aPos.X then begin
            LastPoint := MakePoint( aPos.X, LastPoint.Y ) ;
            if Connect then
              Screen.Cursor := ord( crHandPoint )
            else
              Screen.Cursor := ord( crDrawWand ) ;
          end ;
        dwsVertical :
          if LastPoint.Y <> aPos.Y then begin
            LastPoint := MakePoint( LastPoint.X, aPos.Y ) ;
            if Connect then
              Screen.Cursor := ord( crHandPoint )
            else
              Screen.Cursor := ord( crDrawWand ) ;
          end ;
      end ;
  end ;
end ;

procedure TMouseSchematicDrawer.Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;

  procedure Connect ;
  var
    aObject         : TMedaObject ;
    iLine           : TMedaWire ;
    iPin            : TMedaPin ;
    iPort           : TMedaPort ;
    iPos            : TGPPointF ;
  begin
    if assigned( aViewList ) then begin
      aViewlist.Remove( fLine.View ) ;
      if aViewList.Count > 0 then begin
        aObject := TMedaObject( aViewList.FirstView.Owner ) ;
        if assigned( aObject ) then begin
          if aObject is TMedaWire then begin
            iLine := TMedaWire( aObject ) ;
            iPos := iLine.GetConnector( aPos ) ;
            //            iPos.X := iPos.X - fOffset.X ;
            //            iPos.Y := iPos.Y - fOffset.Y ;
            LastPoint := iPos ;
            if iLine.Net <> fNet then begin
              iLine.Net.Join( fNet ) ;
              fNet.Vaporize ;
              fNet := iLine.Net ;
              fState := dswConnected ;
              Screen.Cursor := crDefault ;
            end ;
          end
          else if aObject is TMedaPin then begin
            iPin := TMedaPin( aObject ) ;
            iPos := iPin.GetConnector( aPos ) ;
            //            iPos.X := iPos.X - fOffset.X ;
            //            iPos.Y := iPos.Y - fOffset.Y ;
            LastPoint := iPos ;
            iPort := iPin.Port ;
            if assigned( iPort ) then begin
              if assigned( iPort.Net ) then begin
                iPort.Net.Join( fNet ) ;
                fNet.Vaporize ;
                fNet := iPort.Net ;
              end
              else
                iPort.Net := fNet ;
              fState := dswConnected ;
              Screen.Cursor := crDefault ;
            end ;
          end ;
        end ;
      end ;
    end ;
  end ;
begin
  if fState <> dwsIdle then begin
    if not ( ssLeft in Shift ) then begin
      ScaleDown( aPos, fGrid ) ;
      ScaleUp( aPos, fGrid ) ;
      if fState in [ dwsHorizontal, dwsVertical ] then
        Connect ;
      if assigned( fNet ) then
        fNet.SetSelection( triFalse ) ;
    end ;
  end ;
  inherited ;
end ;

{ TMousePCBDrawer }

procedure TMousePCBDrawer.AddPoint( aPoint : TGPPointF ) ;
begin
  inherited ;
  fTrack := fNet.AddTrack ;
  fTrack.Path.AddLine( aPoint, aPoint ) ;
  fTrack.Transforms[ 0 ] := fTrans ;
  fTrack.Width := frmMain.DefaultTrackWidth ;
  fTrack.PlaceRef := fPlace ;
  fTrack.PlaceMe ;

  LastPoint := aPoint ;
end ;

function TMousePCBDrawer.GetLastPoint : TGPPointF ;
var
  iPoints           : array[ 0..1 ] of TGPPointF ;
begin
  Result := fTrans.Position ;
  if assigned( fTrack ) then begin
    fTrack.Path.GetPathPoints( PGPPointF( @iPoints[ 0 ] ), 2 ) ;
    Result := iPoints[ 1 ] ;
  end ;
end ;

procedure TMousePCBDrawer.SetLastPoint( const Value : TGPPointF ) ;
var
  iPoints           : array[ 0..1 ] of TGPPointF ;
begin
  if assigned( fTrack ) then begin
    if fTrack.Path.GetPointCount = 2 then begin
      fTrack.Path.GetPathPoints( PGPPointF( @iPoints[ 0 ] ), 2 ) ;
      fTrack.Path.Reset ;
      fTrack.Path.AddLine( iPoints[ 0 ], Value ) ;
    end
    else begin
      fTrack.Path.Reset ;
      fTrack.Path.AddLine( Value, Value ) ;
    end ;
    fTrack.Invalidate ;
  end ;
  inherited ;
end ;

procedure TMousePCBDrawer.Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  iStack            : TMedaStack ;
begin
  inherited ;
  if fState in [ dwsIdle ] then begin
    fNet := nil ;
    if fObject is TMedaPad then begin
      iStack := fObject.Parent as TMedaStack ;
      fPort := iStack.Port as TMedaPort ;
      if assigned( fPort ) then begin
        fPart := TMedaPart( fPort.Parent ) ;
        Assert( assigned( fPart ), 'Port has no Part' ) ;
        fModule := fPart.Module ;       // scope of the port
        Assert( assigned( fModule ), 'Part has no Module' ) ;
        if assigned( fPort.Net ) then
          fNet := fPort.Net
        else begin
          fNet := fModule.AddNet ;
          fPort.Net := fNet ;
        end ;
        fTrans.Position := fObject.GetConnector( aPos ) ;
        fPlace := fObject.PlaceRef ;
        fState := dwsLine ;
        AddPoint( MakePoint( 0.0, 0.0 ) ) ;
      end
      else begin
        Screen.Cursor := crNo ;
        Exit ;
      end ;
    end
    else if fObject is TMedaTrack then begin
      fNet := ( fObject as TMedaTrack ).Net ;
      fTrans.Position := fObject.GetConnector( aPos ) ;
      fPlace := fObject.PlaceRef ;
      fState := dwsLine ;
      AddPoint( MakePoint( 0.0, 0.0 ) ) ;
    end
    else begin
      Screen.Cursor := crNo ;
      Exit ;
    end ;
    Assert( assigned( fNet ), 'Port has no Net' ) ;
    fNet.SetSelection( TriTrue ) ;
    Screen.Cursor := ord( crDrawWand ) ;
  end ;
end ;

procedure TMousePCBDrawer.KeyDown( var Key : Word ; Shift : TShiftState ) ;
begin
  if ( ssCtrl in Shift ) and not ( ssCtrl in fShift ) then
    fState := dwsBend ;
  fShift := Shift ;
end ;

procedure TMousePCBDrawer.Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;

  function Connect : boolean ;
  var
    aObject         : TMedaViewable ;
    i               : integer ;
  begin
    Result := False ;
    if assigned( aViewList ) then
      for i := 0 to aViewList.Count - 1 do begin
        aObject := aViewList[ i ].Owner ;
        if assigned( aObject ) and ( aObject <> fObject ) then begin
          if ( aObject is TMedaTrack ) and ( fObject is TMedaTrack ) then
            Result := True
          else if aObject is TMedaPad then
            Result := True ;
          if Result then
            Exit ;
        end ;
      end ;
  end ;
begin
  inherited ;
  if fState <> dwsIdle then begin
    fShift := Shift ;
    ScaleDown( aPos, fGrid ) ;
    ScaleUp( aPos, fGrid ) ;
    aPos.X := aPos.X - fTrans.Position.X ;
    aPos.Y := aPos.Y - fTrans.Position.Y ;

    if assigned( fNet ) then
      case fState of
        dwsLine : begin
            NewState( aPos ) ;
            if fState <> dwsLine then
              LastPoint := aPos ;
          end ;
        dwsBend : begin
            NewState( aPos ) ;
            if fState <> dwsBend then
              AddPoint( LastPoint ) ;
          end ;
        dwsHorizontal :
          if LastPoint.X <> aPos.X then begin
            LastPoint := MakePoint( aPos.X, LastPoint.Y ) ;
            if Connect then
              Screen.Cursor := ord( crHandPoint )
            else
              Screen.Cursor := ord( crDrawWand ) ;
          end ;
        dwsVertical :
          if LastPoint.Y <> aPos.Y then begin
            LastPoint := MakePoint( LastPoint.X, aPos.Y ) ;
            if Connect then
              Screen.Cursor := ord( crHandPoint )
            else
              Screen.Cursor := ord( crDrawWand ) ;
          end ;
      end ;
  end ;
end ;

procedure TMousePCBDrawer.Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;

  procedure Connect ;
  var
    aObject         : TMedaObject ;
    iTrack          : TMedaTrack ;
    iPort           : TMedaPort ;
    iStack          : TMedaStack ;
    iPad            : TMedaPad ;
    iPos            : TGPPointF ;
  begin
    if assigned( aViewList ) then begin
      aViewlist.Remove( fTrack.View ) ;
      if aViewList.Count > 0 then begin
        aObject := aViewList.FirstView.Owner ;
        if assigned( aObject ) then begin
          if aObject is TMedaTrack then begin
            iTrack := TMedaTrack( aObject ) ;
            iPos := iTrack.GetConnector( aPos ) ;
            iPos.X := iPos.X - fTrans.Position.X ;
            iPos.Y := iPos.Y - fTrans.Position.Y ;
            LastPoint := iPos ;
            if iTrack.Net <> fNet then begin
              iTrack.Net.Join( fNet ) ;
              fNet.Vaporize ;
              fNet := iTrack.Net ;
              fState := dswConnected ;
              Screen.Cursor := crDefault ;
            end ;
          end
          else if aObject is TMedaPad then begin
            iPad := TMedaPad( aObject ) ;
            iPos := iPad.GetConnector( aPos ) ;
            iPos.X := iPos.X - fTrans.Position.X ;
            iPos.Y := iPos.Y - fTrans.Position.Y ;
            LastPoint := iPos ;
            iStack := iPad.Parent as TMedaStack ;
            iPort := iStack.Port ;
            if assigned( iPort ) then begin
              if assigned( iPort.Net ) then begin
                iPort.Net.Join( fNet ) ;
                fNet.Vaporize ;
                fNet := iPort.Net ;
              end
              else
                iPort.Net := fNet ;
              fState := dswConnected ;
              Screen.Cursor := crDefault ;
            end ;
          end ;
        end ;
      end ;
    end ;
  end ;
begin
  if not ( ssLeft in Shift ) then begin
    ScaleDown( aPos, fGrid ) ;
    ScaleUp( aPos, fGrid ) ;
    if fState in [ dwsHorizontal, dwsVertical ] then
      Connect ;
    if assigned( fNet ) then
      fNet.SetSelection( triFalse ) ;
  end ;
  inherited ;
end ;

{ TMouseLink }

constructor TMouseLinker.Create( aGrid : integer ) ;
begin
  inherited Create( aGrid ) ;
end ;

procedure TMouseLinker.Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
  inherited ;
  fLinkedObject := nil ;
  if aViewList.Count = 0 then
    Exit ;
  fObject := aViewList[ 0 ].Owner as TMedaObject ;
  if assigned( fObject ) then
    fLinkedObject := fObject.Link ;
  if assigned( fLinkedObject ) then
    Screen.Cursor := ord( crLinkPoint )
  else
    Screen.Cursor := ord( crLinkQuest ) ;
end ;

procedure TMouseLinker.Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
end ;

procedure TMouseLinker.Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
  inherited ;
  if assigned( fLinkedObject ) then begin
    fLinkedObject.Show ;
    fLinkedObject := nil ;
  end ;
end ;

{ TMouseSelector }

procedure TMouseSelector.Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  i                 : integer ;
begin
  if assigned( aViewList ) then
    for i := 0 to aViewList.Count - 1 do
      with aViewList[ i ] do
        case GetSelection of
          triFalse : SetSelection( triTrue ) ;
          triMaybe : SetSelection( triFalse ) ;
          triTrue : SetSelection( triFalse ) ;
        end ;
end ;

procedure TMouseSelector.Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
end ;

procedure TMouseSelector.Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
end ;

{ TMouseConnector }

procedure TMouseConnector.Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  i                 : integer ;
begin
  if assigned( aViewList ) then
    for i := 0 to aViewList.Count - 1 do
      with aViewList[ i ] do
        case GetSelection of
          triFalse : SetSelection( triTrue ) ;
          triMaybe : SetSelection( triFalse ) ;
          triTrue : SetSelection( triFalse ) ;
        end ;
end ;

procedure TMouseConnector.Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
end ;

procedure TMouseConnector.Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  iModule           : TMedaModule ;
  iPins             : TMedaViewList ;
  iPinView          : TMedaView ;
  iNet, pNet        : TMedaNet ;
  iPort             : TMedaPort ;
  i                 : integer ;
begin
  if ( ssCtrl in Shift ) and assigned( aViewList ) and ( aViewList.Count > 0 ) then begin
    iModule := aViewList[ 0 ].Owner.Module ;
    iPins := TMedaViewList.Create ;
    try
      Project.GetSelectedItems( TObject( iPins ) ) ;
      if iPins.Count > 1 then begin
        iNet := iModule.AddNet ;
        for i := 0 to iPins.Count - 1 do begin
          iPinView := iPins[ i ] as TMedaView ;
          iPinView.SetSelection( triFalse ) ;
          if iPinView.Owner is TMedaPin then
            iPort := TMedaPort( TMedaPin( iPinView.Owner ).Port )
          else if iPinView.Owner is TMedaPad then
            iPort := TMedaPort( TMedaStack( iPinView.Owner.Parent ).Port )
          else
            Continue ;
          pNet := iPort.Net ;
          if not assigned( pNet ) then
            iPort.Net := iNet
          else if pNet <> iNet then
            iNet.Join( pNet ) ;
        end ;
      end ;
    finally
      iPins.Free ;
    end ;
  end ;
end ;

{ TMouseRight }

constructor TMouseRight.Create ;
begin
  inherited Create( aGrid ) ;
  fState := rgtIdle ;
end ;

procedure TMouseRight.Down( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
  inherited ;
end ;

procedure TMouseRight.Move( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
begin
  inherited ;
end ;

procedure TMouseRight.Up( aViewList : TMedaViewList ; Shift : TShiftState ; aPos : TGPPointF ) ;
var
  iPopup            : TPopupMenu ;
  iPoint            : TPoint ;
begin
  inherited ;
  iPoint := Mouse.CursorPos ;
  iPopup := nil ;
  ScaleDown( aPos, fGrid ) ;
  ScaleUp( aPos, fGrid ) ;
  SelectedPoint := aPos ;
  if fViewList.Count > 0 then begin
    SelectedObject := fViewList.FirstView.Owner as TMedaObject ;
    SelectedPlace := fViewList.Place ;
    iPoint := fViewList.FirstView.Show ;
    SelectedObject.SetSelection( triTrue ) ;
    iPopup := SelectedObject.PopupMenu ;
  end
  else begin
    SelectedObject := nil ;
    SelectedPlace := fViewList.Place ;
    if assigned( SelectedPlace ) then
      iPopup := fViewList.Place.PopupMenu ;
  end ;
  if assigned( iPopup ) then
    iPopup.Popup( iPoint.X, iPoint.Y ) ;
end ;

{ TMouseSchematicFactory }

function TMouseSchematicFactory.CreateConnector( aGrid : integer ) : TMouseConnector ;
begin
  Result := TMouseConnector.Create( aGrid ) ;
end ;

function TMouseSchematicFactory.CreateDragger( aGrid : integer ) : TMouseDragger ;
begin
  Result := TMouseSchematicDragger.Create( aGrid ) ;
end ;

function TMouseSchematicFactory.CreateDrawer( aGrid : integer ) : TMouseDrawer ;
begin
  Result := TMouseSchematicDrawer.Create( aGrid ) ;
end ;

function TMouseSchematicFactory.CreateLinker( aGrid : integer ) : TMouseLinker ;
begin
  Result := TMouseLinker.Create( aGrid ) ;
end ;

function TMouseSchematicFactory.CreateRight( aGrid : integer ) : TMouseRight ;
begin
  Result := TMouseRight.Create( aGrid ) ;
end ;

function TMouseSchematicFactory.CreateSelector( aGrid : integer ) : TMouseSelector ;
begin
  Result := TMouseSelector.Create( aGrid ) ;
end ;

{ TMousePCBFactory }

function TMousePCBFactory.CreateConnector( aGrid : integer ) : TMouseConnector ;
begin
  Result := TMouseConnector.Create( aGrid ) ;
end ;

function TMousePCBFactory.CreateDragger( aGrid : integer ) : TMouseDragger ;
begin
  Result := TMousePCBDragger.Create( aGrid ) ;
end ;

function TMousePCBFactory.CreateDrawer( aGrid : integer ) : TMouseDrawer ;
begin
  Result := TMousePCBDrawer.Create( aGrid ) ;
end ;

function TMousePCBFactory.CreateLinker( aGrid : integer ) : TMouseLinker ;
begin
  Result := TMouseLinker.Create( aGrid ) ;
end ;

function TMousePCBFactory.CreateRight( aGrid : integer ) : TMouseRight ;
begin
  Result := TMouseRight.Create( aGrid ) ;
end ;

function TMousePCBFactory.CreateSelector( aGrid : integer ) : TMouseSelector ;
begin
  Result := TMouseSelector.Create( aGrid ) ;
end ;

end.

